import copy
import datetime
import json

from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from model_app.models import BookInfo, HeroInfo
from model_app.ser import BookInfoSerializer, HeroInfoSerializer, BookInfoModelSerializer, HeroInfoModelSerializer

"""
1. 获取所有图书数据
API: GET /books/
参数：无
响应：
  状态码：200
  [
      {
          "id": "图书id",
          "btitle": "图书名称",
          "bpub_date": "出版日期",
          "bread": "阅读量",
          "bcomment": "评论量"
      },
      ...
  ]
"""


class BookView(View):
    def get(self, request, pk=None):
        if pk:
            # 获取某个
            try:
                book = BookInfo.objects.get(id=pk)
            except Exception as e:
                return JsonResponse({'code': 999, 'msg': 'pk不存在'})
            book_data = {
                'id': book.id,
                'btitle': book.btitle,
                'bpub_date': book.bpub_date,
                'bread': book.bread,
                'bcomment': book.bcomment
            }
            return JsonResponse(book_data)

        else:
            # 1. request.GET,   过滤, 排序, 分页
            # 1.3 分页,  页容量, 每页条数,  页面数,   page_size  page
            page_size = int(request.GET.get('page_size', 3))
            page = int(request.GET.get('page', 1))
            # 1.2 排序 ordering=btitle, bread, bcomment
            ordering = request.GET.get('ordering', None)  # 'btitle',  'bread'

            get_dict = copy.copy(request.GET)
            if 'ordering' in request.GET.keys():
                get_dict.pop('ordering')
            if 'page' in request.GET.keys():
                get_dict.pop('page')
            if 'page_size' in request.GET.keys():
                get_dict.pop('page_size')

            filter_fields = ('btitle', 'bcomment')
            query_set = BookInfo.objects.all()

            for k, v in get_dict.items():  # [('btitle', '西游记'), ('bread', '100')]
                if k in filter_fields:
                    query_set = query_set.filter(**{k: v})  # **{'btitle':'西游记'} => btitle='西游记'
                else:
                    return JsonResponse({'code': 999, 'msg': '不允许使用%s字段过滤' % k})
            # 1.1 过滤(精准匹配), 搜索(模糊匹配)?  btitle=三国演义,

            # btitle = request.GET.get('btitle', None)
            # if btitle:
            #     query_set = BookInfo.objects.filter(btitle=btitle)
            #
            # bread = request.GET.get('bread', None)
            #
            # if bread:
            #     query_set = query_set.filter(bread=bread)

            if ordering:
                # 排序
                query_set = query_set.order_by(ordering)  # '-bread'

            # 分页
            query_set = query_set[(page - 1) * page_size:page * page_size]  # sql  =>  offset  limit
            # 列表,  起始下标,  结束下标   1:[0:3]=> 0,1,2    2:[3:6]  3,4,5  3:[6:9]  6,7,8
            # [(page-1)*page_size:page*page_size]

            # 获取很多
            # 1. 获取模型数据

            # 2. 返回json
            book_list = []
            for book in query_set:
                book_data = {
                    'id': book.id,
                    'btitle': book.btitle,
                    'bpub_date': book.bpub_date,
                    'bread': book.bread,
                    'bcomment': book.bcomment
                }
                book_list.append(book_data)

            return JsonResponse(book_list, safe=False)
            # JsonResponse  默认接收的是字典, 如果不是字典, 需要指明safe=False

    def post(self, request):
        #  认证?
        #  权限?
        #  限流?
        #  中间件里实现

        """
        2. 新增一本图书数据
        API: POST /books/
        参数：body  json bytes
          {
              "btitle": "图书名称",
              "bpub_date": "出版日期",
              "bread": 10
          }
        响应：
          状态码：201
          {
              "id": "图书id",
              "btitle": "图书名称",
              "bpub_date": "出版日期",
              "bread": "阅读量",
              "bcomment": "评论量"
          }
        """
        # 创建数据
        data = json.loads(request.body.decode())
        btitle = data.get('btitle', None)
        bpub_date = data.get('bpub_date', None)
        bread = data.get('bread', 0)
        bcomment = data.get('bcomment', 0)

        # 数据校验的依据?   根据模型的类型
        if all([btitle, bpub_date]):
            pass
        else:
            return JsonResponse({'msg': '参数不足'})

        if bread.isdigit():
            pass
        else:
            return JsonResponse({'msg': 'bread类型不正确'})
        if str(bcomment).isdigit():
            pass
        else:
            return JsonResponse({'msg': 'bcomment类型不正确'})

        try:
            datetime.datetime.strptime(bpub_date, '%Y-%m-%d')
        except Exception as e:
            return JsonResponse({'msg': '日期格式有误, 请使用 "YYYY-MM-DD" 格式'})

        book = BookInfo(
            btitle=btitle,
            bpub_date=bpub_date,
            bread=bread,
            bcomment=bcomment
        )
        book.save()
        return JsonResponse({
            'id': book.id,
            "btitle": book.btitle,
            "bpub_date": book.bpub_date,
            "bread": book.bread,
            "bcomment": book.bcomment
        })


#  1. APIview  #  认证, 权限, 限流
#  2. genericAPIView  # query,  serializer
#  3. modelViewSet (List, creaet, update, delete, retrive )

class GetMethodMixin():
    def get(self, request, pk=None):
        print(request.user)  #
        if pk:
            # 获取某个
            try:
                book = BookInfo.objects.get(id=pk)
            except Exception as e:
                return JsonResponse({'code': 999, 'msg': 'pk不存在'})
            book_data = {
                'id': book.id,
                'btitle': book.btitle,
                'bpub_date': book.bpub_date,
                'bread': book.bread,
                'bcomment': book.bcomment
            }
            return JsonResponse(book_data)

        else:
            # 1. request.GET,   过滤, 排序, 分页
            # 1.3 分页,  页容量, 每页条数,  页面数,   page_size  page
            page_size = int(request.GET.get('page_size', 3))
            page = int(request.GET.get('page', 1))
            # 1.2 排序 ordering=btitle, bread, bcomment
            ordering = request.GET.get('ordering', None)  # 'btitle',  'bread'

            get_dict = copy.copy(request.GET)
            if 'ordering' in request.GET.keys():
                get_dict.pop('ordering')
            if 'page' in request.GET.keys():
                get_dict.pop('page')
            if 'page_size' in request.GET.keys():
                get_dict.pop('page_size')

            query_set = self.query_set

            for k, v in get_dict.items():  # [('btitle', '西游记'), ('bread', '100')]
                if k in self.filter_fields:
                    query_set = query_set.filter(**{k: v})  # **{'btitle':'西游记'} => btitle='西游记'
                else:
                    return JsonResponse({'code': 999, 'msg': '不允许使用%s字段过滤' % k})
            # 1.1 过滤(精准匹配), 搜索(模糊匹配)?  btitle=三国演义,

            # btitle = request.GET.get('btitle', None)
            # if btitle:
            #     query_set = BookInfo.objects.filter(btitle=btitle)
            #
            # bread = request.GET.get('bread', None)
            #
            # if bread:
            #     query_set = query_set.filter(bread=bread)

            if ordering:
                # 排序
                query_set = query_set.order_by(ordering)  # '-bread'

            # 分页
            query_set = query_set[(page - 1) * page_size:page * page_size]  # sql  =>  offset  limit
            # 列表,  起始下标,  结束下标   1:[0:3]=> 0,1,2    2:[3:6]  3,4,5  3:[6:9]  6,7,8
            # [(page-1)*page_size:page*page_size]

            # 获取很多
            # 1. 获取模型数据

            # 2. 返回json
            # book_list = []
            # for book in query_set:
            #     book_data = {
            #         'id': book.id,
            #         'btitle': book.btitle,
            #         'bpub_date': book.bpub_date,
            #         'bread': book.bread,
            #         'bcomment': book.bcomment
            #     }
            #     book_list.append(book_data)
            ser = self.ser(query_set, many=True)

            return JsonResponse(ser.data, safe=False)
            # JsonResponse  默认接收的是字典, 如果不是字典, 需要指明safe=False


class PostMethodMixin():
    def post(self, request):
        ser = self.ser(data=request.data)
        # 序列化器装载数据

        if ser.is_valid():  # True, False,   序列化器校验数据
            object = ser.save()
            # 序列化器保存数据数据
        else:
            return JsonResponse({'msg': ser.errors})  # 返回错误
        return JsonResponse(ser.data, status=201)  # 返回结果


class BookInfoAPIView(GetMethodMixin, PostMethodMixin, APIView):
    # 带了认证权限限流
    permission_classes = (AllowAny,)  # 需要认证用户  权限

    ser = BookInfoModelSerializer
    query_set = BookInfo.objects.all()
    filter_fields = ('btitle', 'bcomment')

    # post, put,  patch


class HeroInfoAPIView(GetMethodMixin, PostMethodMixin, APIView):
    query_set = HeroInfo.objects.all()
    ser = HeroInfoModelSerializer
    # filter_fields = ('hname', 'hcomment')


class MyPageNumberPagination(PageNumberPagination):
    # 用哪个参数来传  一页多少个数据,
    page_size_query_param = 'ps'


# viewset
class BookInfoModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer
    search_fields = ('=btitle', '=bread')
    ordering_fields = ('bread', 'bcomment')

    pagination_class = MyPageNumberPagination

    # ?search=西游记
    # filter_fields = ('btitle', 'bcomment')
    # /books/is_del/
    @action(methods=['get'], detail=False)
    def is_del(self, request):
        # 获取删除的图书列表
        queryset = self.queryset.filter(is_delete=True)
        ser = self.serializer_class(queryset, many=True)
        return JsonResponse(ser.data, safe=False)

    @action(methods=['get'], detail=False)
    def set_del(self, request):
        # 把所有图书全部设置为删除
        queryset = self.queryset.update(is_delete=True)
        return JsonResponse({'msg': 'ok'})

    # /books/pk/only_title/
    @action(methods=['get'], detail=True)
    def only_title(self, request, pk):
        # 如果带pk, self, 中提供了,  根据pk获取的那个对象
        instance = self.get_object()  # 根据pk 获取到的数据
        return JsonResponse({'btitle': instance.btitle})



